import React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators as bind} from 'redux';
import {Spin, message, Modal} from 'antd';
import {isEmpty, flatten, reduce, get, isArray, isFunction} from 'lodash';
import global from '../../global';
import {
    dataKey, nullKey,
    stateKey, errorKey
} from '../../util/bed';
import {actions} from '../../store';
import {formatError} from './util';

/**
 * redux访问高阶组件，封装connect方法和忙碌状态以及错误处理
 * @param module 模块名称（可以带.嵌套）
 * @param option 数据访问配置
 *
 * @param ui 显示相关参数
 * @return {function(*): *}
 */
export default (module, option, ui = {}) => {
    // 映射参数处理
    switch (typeof option) {
    case 'string':
        option = {data: option};
        break;
    case 'undefined':
        option = {actions: 'load'};
        break;
    case 'object':
        if (isArray(option)) option = {actions: option};
        break;
    }
    const {
        data = dataKey,
        prefix = '',
        loader,
        parser,
        actionsOnly,
        //loadArgs //load加载参数d12
    } = option;

    // 数据映射
    const stateMap = (state, props) => {
        let key;
        switch (typeof data) {
        case 'string':
            key = data;
            break;
        case 'function':
            // 从属性中获取数据标识
            key = data(props);
            break;
        }
        if (!key) key = nullKey;
        const map = {
            [prefix + 'busy']: get(state, `${module}.${stateKey}.${key}`),
            [prefix + 'error']: get(state, `${module}.${errorKey}.${key}`)
        };
        if (!actionsOnly) {
            const x = get(state, `${module}.${key}`);
            map[prefix + 'data'] = parser
                ? parser(x, id => get(state, `${module}.${id}`), props, state)
                : x;
        }

        if (global.debug) {
            for (const i in map) {
                /*eslint-disable*/
                if (props.hasOwnProperty(i)) {
                    console.error(`props已经存在属性:${i},该属性将被重写`, props);
                }
                /*eslint-enable*/
            }
        }
        return map;
    };

    // 动作映射
    let dispatchMap;
    if (!isEmpty(option.actions)) {
        dispatchMap = dispatch => reduce(flatten([option.actions]), (result, a) => {
            let name = a;
            if (typeof a === 'object') {
                for (const x in a) {
                    name = a[x];
                    a = x;
                    break;
                }
            }
            const action = get(actions, `${module}.${a}`);
            if (action) {
                result[`${prefix}${name}`] = bind(action, dispatch);
            }
            return result;
        }, {});
    }

    // 显示参数处理
    if (typeof ui === 'boolean') {
        ui = {showLoading: ui};
    }
    const {
        loadingText,
        loadingSize,
        showLoading = true
    } = ui;

    return Wrapped => @connect(stateMap, dispatchMap)
    class InnerComponent extends React.Component {
        componentDidMount() {
            const {[`${prefix}load`]: load} = this.props;
            if (typeof loader === 'function') {
                loader(this.props);
            } else if (typeof load === 'function') {
                let {loadArgs} = option;
                if (loadArgs) {
                    if (isFunction(loadArgs)) {
                        loadArgs = loadArgs(this.props);
                    }
                    if (!isArray(loadArgs)) {
                        loadArgs = loadArgs === undefined ? [] : [loadArgs];
                    }
                } else {
                    loadArgs = [];
                }
                load(...loadArgs);
            }
        }

        componentWillReceiveProps(props) {
            const kError = `${prefix}error`;
            const {[kError]: error} = props;
            if (error && error !== this.props[kError]) {
                const {status} = error;
                let {message: err} = error;
                const len = err.length;
                const showDialog = len > 80;
                if (showDialog) {
                    if (process.env.NODE_ENV === 'production') {
                        switch (status) {
                        case 500:
                            err = '服务器错误，请稍候重试';
                            break;
                        case 401:
                            err = '尚未登录';
                            break;
                        }
                    }
                }
                if (showDialog) {
                    let width;
                    if (len > 100) {
                        width = 600;
                    }
                    Modal.error({
                        title: `错误${status || ''}`,
                        content: err,
                        width
                    });
                } else {
                    message.error(formatError({
                        status, message: err
                    }));
                }
            }
        }

        render() {
            const {[prefix + 'busy']: busy, visible = true} = this.props;
            const loading = !!busy && showLoading && visible;
            return (
                <Spin tip={loadingText} size={loadingSize} spinning={loading}>
                    <Wrapped {...this.props}/>
                </Spin>
            );
        }
    }
    ;
};
